package cn.kow.kmall.service.impl;

import cn.kow.kmall.common.constant.KmallConstants;
import cn.kow.kmall.common.enums.ItemStatusEnum;
import cn.kow.kmall.common.enums.KmallResultEnum;
import cn.kow.kmall.common.util.ItemUtils;
import cn.kow.kmall.core.constant.KmallStatusConstant;
import cn.kow.kmall.core.exception.ServiceException;
import cn.kow.kmall.core.util.JsonUtils;
import cn.kow.kmall.core.util.MoneyUtils;
import cn.kow.kmall.dao.ItemAttributeRepository;
import cn.kow.kmall.dao.ItemRepository;
import cn.kow.kmall.dao.SkuRepository;
import cn.kow.kmall.pojo.dto.*;
import cn.kow.kmall.pojo.entity.Item;
import cn.kow.kmall.pojo.entity.ItemAttribute;
import cn.kow.kmall.pojo.entity.Sku;
import cn.kow.kmall.service.ItemService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: lijun
 * @Description:
 * @Date: Created in 2019-05-24 18:08
 * @Modified By:
 */
@Service("itemService")
public class ItemServiceImpl implements ItemService {

    /**
     * 商品表Repository
     */
    @Autowired
    private ItemRepository itemRepository;

    /**
     * SKU表Repository
     */
    @Autowired
    private SkuRepository skuRepository;

    /**
     * 商品属性表Repository
     */
    @Autowired
    private ItemAttributeRepository itemAttributeRepository;

    @Override
    public Item getItemById(Long itemId) {
        Item exampleItem = new Item();
        exampleItem.setId(itemId);
        exampleItem.setStatus(KmallStatusConstant.NORMAL);
        exampleItem.setDeleted(false);
        Example<Item> example = Example.of(exampleItem);
        Item item = itemRepository.findOne(example).orElseThrow(() -> new ServiceException(KmallResultEnum.ITEM_NOT_FIND));
        return item;
    }

    @Override
    public void remove(List<Long> ids) {
        itemRepository.deleteAllById(ids);
    }

    @Override
    public void updateItemOnline(List<Long> ids, String operator) {
        List<Item> itemList = itemRepository.findAllById(ids);
        Date updateTime = new Date();
        itemList.stream().filter(i -> !ItemStatusEnum.ONLINE.getValue().equals(i.getItemStatus())).forEach(i -> {
            i.setItemStatus(ItemStatusEnum.ONLINE.getValue());
            i.setUpdateBy(operator);
            i.setUpdateTime(updateTime);
        });
        itemRepository.saveAll(itemList);
    }

    @Override
    public void updateItemOffline(List<Long> ids, String operator) {
        List<Item> itemList = itemRepository.findAllById(ids);
        Date updateTime = new Date();
        itemList.stream().filter(i -> ItemStatusEnum.ONLINE.getValue().equals(i.getItemStatus())).forEach(i -> {
            i.setItemStatus(ItemStatusEnum.OFFLINE.getValue());
            i.setUpdateBy(operator);
            i.setUpdateTime(updateTime);
        });
        itemRepository.saveAll(itemList);
    }

    @Override
    public List<Item> listItemByIds(List<Long> itemIdList) {
       return itemRepository.findAllById(itemIdList);
    }

    @Override
    public Page<Item> listByPage(ItemQueryDTO queryDTO) {
        return itemRepository.queryByPage(queryDTO);
    }

    @Override
    public List<ItemListDTO> queryItemList(ItemQueryDTO queryDTO) {
        Page<Item> page = listByPage(queryDTO);
        List<Item> itemList = page.getContent();
        List<ItemListDTO> itemDTOList = new ArrayList<>();
        for (Item item : itemList) {
            List<Sku> skuList = listSkuByItemId(item.getId());
            Sku sku = skuList.stream().filter(s -> ItemStatusEnum.ONLINE.getValue().equals(s.getSkuStatus())).min(Comparator.comparing(Sku::getSellingPrice)).get();
            ItemListDTO itemDTO = ItemListDTO.builder()
                    .itemId(item.getId())
                    .categoryId(item.getCategoryId())
                    .itemName(item.getName())
                    .simpleDesc(item.getSimpleDesc())
                    .simpleDescFlag(false)
                    .itemImage(item.getPrimaryPic())
                    .soldOut(false)
                    .limitedTag("")
                    .limitedTagFlag(false)
                    .itemTagList(new ArrayList<>())
                    .sellingPrice(MoneyUtils.Fen2YuanStr(sku.getSellingPrice()))
                    .build();
            itemDTOList.add(itemDTO);
        }
        return itemDTOList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Item saveItem(ItemEditDTO itemDTO) {
        String operator = itemDTO.getOperator();

        Item item = new Item();
        assemblerItem(item, itemDTO);
        item.setCreateBy(operator);
        item.setUpdateBy(operator);
        item = itemRepository.create(item);
        long itemId = item.getId();

        // 商品规格创建
        List<ItemSpecDTO> specs = buildSpecList(itemId, itemDTO.getSpecList());
        item.setItemSpec(JsonUtils.toJson(specs, false));

        // 商品SKU创建
        List<ItemSkuDTO> skuList = itemDTO.getSkuList();
        for (ItemSkuDTO itemSku : skuList) {
            itemSku.setItemId(item.getId());
            itemSku.setSkuName(item.getName());
            itemSku.setSkuPic(item.getPrimaryPic());
            saveItemSku(itemSku, specs, operator);
        }

        // 商品属性创建
        saveItemAttribute(itemDTO.getAttrList(), itemId, operator);
        itemRepository.update(item);
        return item;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Item updateItem(ItemEditDTO itemDTO) {
        long itemId = itemDTO.getItemId();
        String operator = itemDTO.getOperator();
        Item item = itemRepository.getById(itemId);
        if (null == item) {
            throw new ServiceException(KmallResultEnum.ITEM_NOT_FIND);
        }
        assemblerItem(item, itemDTO);
        item.setUpdateBy(operator);

        // 商品规格创建
        List<ItemSpecDTO> specs = buildSpecList(itemId, itemDTO.getSpecList());
        item.setItemSpec(JsonUtils.toJson(specs, false));

        // 商品SKU创建
        List<Sku> skuList = skuRepository.listAll(new Sku());
        List<Long> skuIds = new ArrayList<>();
        for (ItemSkuDTO itemSku : itemDTO.getSkuList()) {
            itemSku.getSkuId();
            itemSku.setItemId(item.getId());
            itemSku.setSkuName(item.getName());
            itemSku.setSkuPic(item.getPrimaryPic());
            Sku sku = saveItemSku(itemSku, specs, operator);
            skuIds.add(sku.getId());
        }

        // 删除无用SKU
        if (CollectionUtils.isNotEmpty(skuList)) {
            List<Long> delIds = skuList.stream().map(o -> o.getId()).filter(o -> !skuIds.contains(o)).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(delIds)) {
                skuRepository.deleteAllById(delIds);
            }
        }

        // 商品属性
        itemAttributeRepository.deleteByItemId(itemId);
        saveItemAttribute(itemDTO.getAttrList(), itemId, operator);

        itemRepository.update(item);
        return item;
    }

    private List<ItemSpecDTO> buildSpecList(Long itemId, List<ItemEditDTO.ItemSpec> itemSpecList) {
        List<ItemSpecDTO> specs = new ArrayList<>();
        for (int i = 0; i < itemSpecList.size(); i++) {
            ItemEditDTO.ItemSpec itemSpec = itemSpecList.get(i);
            List<ItemEditDTO.ItemSpecOption> itemSpecOptionList = itemSpec.getOptions();
            List<ItemSpecOptionDTO> optionList = new ArrayList<>();
            for (int j = 0;  j < itemSpecOptionList.size(); j++) {
                ItemEditDTO.ItemSpecOption itemSpecOption = itemSpecOptionList.get(j);
                ItemSpecOptionDTO specOption = ItemSpecOptionDTO.builder().id(itemId + "" + (i + 1) + "" + (j + 1)).option(itemSpecOption.getOption()).build();
                optionList.add(specOption);
            }
            specs.add(ItemSpecDTO.builder().id(itemId + "" + (i + 1)).name(itemSpec.getName()).options(optionList).build());
        }
        return specs;
    }

    private Sku saveItemSku(ItemSkuDTO itemSku, List<ItemSpecDTO> specs, String operator) {
        Sku sku;
        if (null == itemSku.getSkuId()) {
            sku = new Sku();
            sku.setCreateBy(operator);
        } else {
            sku = skuRepository.getById(itemSku.getSkuId());
        }
        assemblerSku(sku, itemSku);
        sku.setUpdateBy(operator);

        // 规格设置
        Map<String, ItemSkuDTO.SpecOption> skuOptionMap = itemSku.getSpecOptions().stream()
                .collect(Collectors.toMap(ItemSkuDTO.SpecOption::getSpec, a -> a, (k1, k2) -> k1));
        List<String> skuSpecIds = new ArrayList<>();
        List<String> skuSpecNames = new ArrayList<>();
        for (ItemSpecDTO specDTO : specs) {
            String specName = specDTO.getName();
            List<ItemSpecOptionDTO> optionList = specDTO.getOptions();
            boolean chooseSpec = false;
            ItemSkuDTO.SpecOption skuOption = skuOptionMap.get(specName);
            for (ItemSpecOptionDTO specOption : optionList) {
                if (specOption.getOption().equals(skuOption.getOption())) {
                    skuSpecIds.add(String.valueOf(specOption.getId()));
                    skuSpecNames.add(specName + ":" + specOption.getOption());
                    chooseSpec = true;
                    break;
                }
            }
            if (!chooseSpec) {
                throw new ServiceException(KmallConstants.FAIL, "sku规格信息错误");
            }
        }
        sku.setSkuSpecId(String.join("^", skuSpecIds));
        sku.setSkuSpecName(String.join(";", skuSpecNames));

        if (null == itemSku.getSkuId()) {
            return skuRepository.create(sku);
        } else {
            return skuRepository.update(sku);
        }
    }

    private void assemblerItem(Item item, ItemEditDTO itemDTO) {
        item.setName(itemDTO.getItemName());
        item.setCategoryId(itemDTO.getCategoryId());
        item.setPrimaryPic(itemDTO.getPrimaryPic());
        item.setScenePic(itemDTO.getPrimaryPic());
        item.setWhitePic(itemDTO.getPrimaryPic());
        item.setSwiperPic(String.join(",", itemDTO.getSwiperPics()));
        item.setDetail(itemDTO.getDetail());
        item.setItemStatus(itemDTO.getItemStatus());
        item.setSort(itemDTO.getSort());
        item.setRemark(itemDTO.getRemark());
    }

    private void assemblerSku(Sku sku, ItemSkuDTO skuDTO) {
        sku.setItemId(skuDTO.getItemId());
        sku.setItemNo(skuDTO.getItemNo());
        sku.setItemName(skuDTO.getSkuName());
        sku.setSkuPic(skuDTO.getSkuPic());
        sku.setSkuStatus(skuDTO.getSkuStatus());
        sku.setStockNum(skuDTO.getStockNum());
        sku.setSellingPrice(MoneyUtils.Yuan2Fen(skuDTO.getSellingPrice()));
    }

    private void saveItemAttribute(List<ItemAttributeDTO> attrList, Long itemId, String operator) {
        for (ItemAttributeDTO attributeDTO : attrList) {
            ItemAttribute itemAttribute = new ItemAttribute();
            itemAttribute.setItemId(itemId);
            itemAttribute.setName(attributeDTO.getAttrName());
            itemAttribute.setValue(attributeDTO.getAttrValue());
            itemAttribute.setCreateBy(operator);
            itemAttribute.setUpdateBy(operator);
            itemAttributeRepository.create(itemAttribute);
        }
    }

    @Override
    public Sku getSkuById(Long skuId) {
        Sku exampleSku = new Sku();
        exampleSku.setId(skuId);
        exampleSku.setStatus(KmallStatusConstant.NORMAL);
        Example<Sku> example = Example.of(exampleSku);
        Sku sku = skuRepository.findOne(example).orElseThrow(() -> new ServiceException(KmallResultEnum.ITEM_NOT_FIND));
        return sku;
    }

    @Override
    public List<Sku> listSkuByItemId(Long itemId) {
        Sku sku = new Sku();
        sku.setItemId(itemId);
        sku.setStatus(KmallStatusConstant.NORMAL);
        List<Sku> skuList = skuRepository.listAll(sku);
        return skuList;
    }

    @Override
    public List<Sku> listSkuByIds(List<Long> skuIds) {
        return skuRepository.findAllById(skuIds);
    }

    @Override
    public List<ItemAttribute> listItemAttribute(Long itemId) {
        ItemAttribute attr = new ItemAttribute();
        attr.setItemId(itemId);
        attr.setStatus(KmallStatusConstant.NORMAL);
        List<ItemAttribute> list = itemAttributeRepository.listAll(attr);
        return list;
    }

    @Override
    public List<ItemCardDTO> listItemCardBySkuIds(List<Long> skuIds) {
        List<Sku> skuList = listSkuByIds(skuIds);
        if (CollectionUtils.isEmpty(skuList)) {
            return null;
        }
        List<Long> itemIds = skuList.stream().map(i -> i.getItemId()).distinct().collect(Collectors.toList());
        List<Item> itemList = listItemByIds(itemIds);
        Map<Long, Item> itemMap = itemList.stream().collect(Collectors.toMap(Item::getId, Function.identity(), (k1,k2) -> k1));
        List<ItemCardDTO> itemCardList = new ArrayList<>();
        for (Sku sku : skuList) {
            long itemId = sku.getItemId();
            Item item = itemMap.get(itemId);
            if (item == null) {
                continue;
            }
            ItemCardDTO itemCard = new ItemCardDTO();
            itemCard.setItemId(item.getId());
            itemCard.setItemNo(sku.getItemNo());
            itemCard.setItemStatus(item.getItemStatus());
            itemCard.setItemName(item.getName());
            itemCard.setItemImage(item.getPrimaryPic());
            itemCard.setSkuId(sku.getId());
            itemCard.setItemSpec(ItemUtils.formatSkuSpecName(sku.getSkuSpecName()));
            itemCard.setMarketPrice(sku.getMarketPrice());
            itemCard.setSellingPrice(sku.getSellingPrice());
            itemCardList.add(itemCard);
        }
        return itemCardList;
    }
}
